package com.xiaoyu.awakening.common.core.kit;

import lombok.Getter;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.annotation.Annotation;
import java.util.Map;

/**
 * spring bean kit
 *
 * @author wangxiaoyu
 * @since v1.0
 */
public class SpringBeanKit implements ApplicationContextAware {

    /**
     * -- GETTER --
     *  获取上下文
     *
     */
    @Getter
    private static ApplicationContext applicationContext;

    /**
     * 注入context
     *
     * @param context ApplicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }

    public static void setApplication(ApplicationContext context) {
        applicationContext = context;
    }

    /**
     * 根据名称获取
     *
     * @param beanName beanName
     * @return 获取对象
     */
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    /**
     * 根据名称和类型
     *
     * @param beanName beanName
     * @param clz      clz
     */
    public static <T> T getBean(String beanName, Class<T> clz) {
        return applicationContext.getBean(beanName, clz);
    }

    /**
     * 根据类型获取bean
     *
     * @param clz clz
     */
    public static <T> T getBean(Class<T> clz) {
        return applicationContext.getBean(clz);
    }


    /**
     * 根据类型获取beanName
     *
     * @param clz clz
     */
    public static String[] getBeanNamesForType(Class<?> clz) {
        return applicationContext.getBeanNamesForType(clz);
    }

    /**
     * 根据类型获取beanMap
     *
     * @param clz clz
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> clz) {
        return applicationContext.getBeansOfType(clz);
    }

    /**
     * 根据bean上的注解获取bean
     *
     * @param clz clz
     */
    public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> clz) {
        return applicationContext.getBeansWithAnnotation(clz);
    }

    /**
     * 获取beanFactory
     *
     */
    public static DefaultListableBeanFactory getBeanFactory() {
        return (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
    }

    /**
     * 销毁bean
     *
     * @param beanName beanName
     */
    public static boolean destroy(String beanName) {
        DefaultListableBeanFactory beanFactory = getBeanFactory();
        if (!beanFactory.containsBean(beanName)) {
            return false;
        }
        beanFactory.destroySingleton(beanName);
        beanFactory.destroyBean(beanName);
        beanFactory.removeBeanDefinition(beanName);
        return true;
    }

    /**
     * 动态注册bean
     *
     * @param beanName beanName
     * @param clz      clz
     */
    public static <T> T register(String beanName, Class<T> clz) {
        DefaultListableBeanFactory beanFactory = getBeanFactory();
        if (!beanFactory.containsBean(beanName)) {
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(clz);
            beanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        }
        return getBean(beanName, clz);
    }

    /**
     * 动态注册bean
     *
     * @param beanName              beanName
     * @param beanDefinitionBuilder beanDefinitionBuilder
     */
    public static Object register(String beanName, BeanDefinitionBuilder beanDefinitionBuilder) {
        DefaultListableBeanFactory beanFactory = getBeanFactory();
        if (!beanFactory.containsBean(beanName)) {
            beanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        }
        return getBean(beanName);
    }

}